home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
C/C++ Users Group Library 1996 July
/
C-C++ Users Group Library July 1996.iso
/
vol_300
/
365_01
/
ex.c
< prev
next >
Wrap
C/C++ Source or Header
|
1992-04-04
|
17KB
|
723 lines
/* ex.c */
/* Author:
* Steve Kirkendall
* 14407 SW Teal Blvd. #C
* Beaverton, OR 97005
* kirkenda@cs.pdx.edu
*/
/* This file contains the code for reading ex commands. */
#include "config.h"
#include "ctype.h"
#include "vi.h"
/* This data type is used to describe the possible argument combinations */
typedef short ARGT;
#define FROM 1 /* allow a linespec */
#define TO 2 /* allow a second linespec */
#define BANG 4 /* allow a ! after the command name */
#define EXTRA 8 /* allow extra args after command name */
#define XFILE 16 /* expand wildcards in extra part */
#define NOSPC 32 /* no spaces allowed in the extra part */
#define DFLALL 64 /* default file range is 1,$ */
#define DFLNONE 128 /* no default file range */
#define NODFL 256 /* do not default to the current file name */
#define EXRCOK 512 /* can be in a .exrc file */
#define NL 1024 /* if mode!=MODE_EX, then write a newline first */
#define PLUS 2048 /* allow a line number, as in ":e +32 foo" */
#define ZERO 4096 /* allow 0 to be given as a line number */
#define NOBAR 8192 /* treat following '|' chars as normal */
#define FILES (XFILE + EXTRA) /* multiple extra files allowed */
#define WORD1 (EXTRA + NOSPC) /* one extra word allowed */
#define FILE1 (FILES + NOSPC) /* 1 file allowed, defaults to current file */
#define NAMEDF (FILE1 + NODFL) /* 1 file allowed, defaults to "" */
#define NAMEDFS (FILES + NODFL) /* multiple files allowed, default is "" */
#define RANGE (FROM + TO) /* range of linespecs allowed */
#define NONE 0 /* no args allowed at all */
/* This array maps ex command names to command codes. The order in which
* command names are listed below is significant -- ambiguous abbreviations
* are always resolved to be the first possible match. (e.g. "r" is taken
* to mean "read", not "rewind", because "read" comes before "rewind")
*/
static struct
{
char *name; /* name of the command */
CMD code; /* enum code of the command */
void (*fn)();/* function which executes the command */
ARGT argt; /* command line arguments permitted/needed/used */
}
cmdnames[] =
{ /* cmd name cmd code function arguments */
{"append", CMD_APPEND, cmd_append, FROM+ZERO+BANG },
#ifdef DEBUG
{"bug", CMD_DEBUG, cmd_debug, RANGE+BANG+EXTRA+NL},
#endif
{"change", CMD_CHANGE, cmd_append, RANGE+BANG },
{"delete", CMD_DELETE, cmd_delete, RANGE+WORD1 },
{"edit", CMD_EDIT, cmd_edit, BANG+FILE1+PLUS },
{"file", CMD_FILE, cmd_file, NAMEDF },
{"global", CMD_GLOBAL, cmd_global, RANGE+BANG+EXTRA+DFLALL+NOBAR},
{"insert", CMD_INSERT, cmd_append, FROM+BANG },
{"join", CMD_INSERT, cmd_join, RANGE+BANG },
{"k", CMD_MARK, cmd_mark, FROM+WORD1 },
{"list", CMD_LIST, cmd_print, RANGE+NL },
{"move", CMD_MOVE, cmd_move, RANGE+EXTRA },
{"next", CMD_NEXT, cmd_next, BANG+NAMEDFS },
{"Next", CMD_PREVIOUS, cmd_next, BANG },
{"print", CMD_PRINT, cmd_print, RANGE+NL },
{"quit", CMD_QUIT, cmd_xit, BANG },
{"read", CMD_READ, cmd_read, FROM+ZERO+NAMEDF},
{"substitute", CMD_SUBSTITUTE, cmd_substitute, RANGE+EXTRA },
{"to", CMD_COPY, cmd_move, RANGE+EXTRA },
{"undo", CMD_UNDO, cmd_undo, NONE },
{"vglobal", CMD_VGLOBAL, cmd_global, RANGE+EXTRA+DFLALL+NOBAR},
{"write", CMD_WRITE, cmd_write, RANGE+BANG+FILE1+DFLALL},
{"xit", CMD_XIT, cmd_xit, BANG+NL },
{"yank", CMD_YANK, cmd_delete, RANGE+WORD1 },
{"!", CMD_BANG, cmd_shell, EXRCOK+RANGE+NAMEDFS+DFLNONE+NL+NOBAR},
{"#", CMD_NUMBER, cmd_print, RANGE+NL },
{"<", CMD_SHIFTL, cmd_shift, RANGE },
{">", CMD_SHIFTR, cmd_shift, RANGE },
{"=", CMD_EQUAL, cmd_file, RANGE },
{"&", CMD_SUBAGAIN, cmd_substitute, RANGE },
#ifndef NO_AT
{"@", CMD_AT, cmd_at, EXTRA },
#endif
#ifndef NO_ABBR
{"abbreviate", CMD_ABBR, cmd_map, EXRCOK+BANG+EXTRA},
#endif
{"args", CMD_ARGS, cmd_args, EXRCOK+NAMEDFS },
#ifndef NO_ERRLIST
{"cc", CMD_CC, cmd_make, BANG+FILES },
#endif
{"cd", CMD_CD, cmd_cd, EXRCOK+BANG+NAMEDF},
{"copy", CMD_COPY, cmd_move, RANGE+EXTRA },
#ifndef NO_DIGRAPH
{"digraph", CMD_DIGRAPH, cmd_digraph, EXRCOK+BANG+EXTRA},
#endif
#ifndef NO_ERRLIST
{"errlist", CMD_ERRLIST, cmd_errlist, BANG+NAMEDF },
#endif
{"ex", CMD_EDIT, cmd_edit, BANG+FILE1 },
{"mark", CMD_MARK, cmd_mark, FROM+WORD1 },
#ifndef NO_MKEXRC
{"mkexrc", CMD_MKEXRC, cmd_mkexrc, NAMEDF },
#endif
{"number", CMD_NUMBER, cmd_print, RANGE+NL },
{"put", CMD_PUT, cmd_put, FROM+ZERO+WORD1 },
{"set", CMD_SET, cmd_set, EXRCOK+EXTRA },
{"shell", CMD_SHELL, cmd_shell, NL },
{"source", CMD_SOURCE, cmd_source, EXRCOK+NAMEDF },
#ifdef SIGTSTP
{"stop", CMD_STOP, cmd_suspend, NONE },
#endif
{"tag", CMD_TAG, cmd_tag, BANG+WORD1 },
{"version", CMD_VERSION, cmd_version, EXRCOK+NONE },
{"visual", CMD_VISUAL, cmd_edit, BANG+NAMEDF },
{"wq", CMD_WQUIT, cmd_xit, NL },
#ifdef DEBUG
{"debug", CMD_DEBUG, cmd_debug, RANGE+BANG+EXTRA+NL},
{"validate", CMD_VALIDATE, cmd_validate, BANG+NL },
#endif
{"chdir", CMD_CD, cmd_cd, EXRCOK+BANG+NAMEDF},
#ifndef NO_COLOR
{"color", CMD_COLOR, cmd_color, EXRCOK+EXTRA },
#endif
#ifndef NO_ERRLIST
{"make", CMD_MAKE, cmd_make, BANG+NAMEDFS },
#endif
{"map", CMD_MAP, cmd_map, EXRCOK+BANG+EXTRA},
{"previous", CMD_PREVIOUS, cmd_next, BANG },
{"rewind", CMD_REWIND, cmd_next, BANG },
#ifdef SIGTSTP
{"suspend", CMD_SUSPEND, cmd_suspend, NONE },
#endif
{"unmap", CMD_UNMAP, cmd_map, EXRCOK+BANG+EXTRA},
#ifndef NO_ABBR
{"unabbreviate",CMD_UNABBR, cmd_map, EXRCOK+WORD1 },
#endif
{(char *)0}
};
/* This function parses a search pattern - given a pointer to a / or ?,
* it replaces the ending / or ? with a \0, and returns a pointer to the
* stuff that came after the pattern.
*/
char *parseptrn(ptrn)
REG char *ptrn;
{
REG char *scan;
for (scan = ptrn + 1;
*scan && *scan != *ptrn;
scan++)
{
/* allow backslashed versions of / and ? in the pattern */
if (*scan == '\\' && scan[1] != '\0')
{
scan++;
}
}
if (*scan)
{
*scan++ = '\0';
}
return scan;
}
/* This function parses a line specifier for ex commands */
char *linespec(s, markptr)
REG char *s; /* start of the line specifier */
MARK *markptr; /* where to store the mark's value */
{
long num;
REG char *t;
/* parse each ;-delimited clause of this linespec */
do
{
/* skip an initial ';', if any */
if (*s == ';')
{
s++;
}
/* skip leading spaces */
while (isspace(*s))
{
s++;
}
/* dot means current position */
if (*s == '.')
{
s++;
*markptr = cursor;
}
/* '$' means the last line */
else if (*s == '$')
{
s++;
*markptr = MARK_LAST;
}
/* digit means an absolute line number */
else if (isdigit(*s))
{
for (num = 0; isdigit(*s); s++)
{
num = num * 10 + *s - '0';
}
*markptr = MARK_AT_LINE(num);
}
/* appostrophe means go to a set mark */
else if (*s == '\'')
{
s++;
*markptr = m_tomark(cursor, 1L, (int)*s);
s++;
}
/* slash means do a search */
else if (*s == '/' || *s == '?')
{
/* put a '\0' at the end of the search pattern */
t = parseptrn(s);
/* search for the pattern */
*markptr &= ~(BLKSIZE - 1);
if (*s == '/')
{
pfetch(markline(*markptr));
if (plen > 0)
*markptr += plen - 1;
*markptr = m_fsrch(*markptr, s);
}
else
{
*markptr = m_bsrch(*markptr, s);
}
/* adjust command string pointer */
s = t;
}
/* if linespec was faulty, quit now */
if (!*markptr)
{
return s;
}
/* maybe add an offset */
t = s;
if (*t == '-' || *t == '+')
{
s++;
for (num = 0; isdigit(*s); s++)
{
num = num * 10 + *s - '0';
}
if (num == 0)
{
num = 1;
}
*markptr = m_updnto(*markptr, num, *t);
}
} while (*s == ';' || *s == '+' || *s == '-');
/* protect against invalid line numbers */
num = markline(*markptr);
if (num < 1L || num > nlines)
{
msg("Invalid line number -- must be from 1 to %ld", nlines);
*markptr = MARK_UNSET;
}
return s;
}